package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.system.domain.SysMenu;
import com.hivekion.system.domain.vo.*;
import com.hivekion.system.mapper.SysMenuMapper;
import com.hivekion.system.service.ISysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl implements ISysMenuService {

      @Autowired
      SysMenuMapper menuMapper;
      @Autowired
      RedisUtil redisUtil;

      @Override
      public List<SysMenu> getMenuList() {
	    if (redisUtil.hasKey(SystemConstant.redis_menu_data)) {
		  List<SysMenu> list =
			  JSON.parseArray(
				  redisUtil.get(SystemConstant.redis_menu_data).toString(),
				  SysMenu.class);
		  return list;
	    } else {
		  List<SysMenu> list = menuMapper.selectList(null);
		  redisUtil.set(SystemConstant.redis_menu_data, JSON.toJSONString(list));
		  return list;
	    }
      }

      private void updateRedis() {
	    List<SysMenu> list = menuMapper.selectList(null);
	    redisUtil.set(SystemConstant.redis_menu_data, JSON.toJSONString(list));
      }

      @Override
      public SysMenuModelVo getInfo(String menuId) {
	    SysMenu menu = menuMapper.selectById(menuId);
	    if (menu == null) {
		  throw new BusinessException(500, "未找到对象");
	    }
	    SysMenuModelVo vo = new SysMenuModelVo();
	    BeanUtils.copyProperties(menu, vo);
	    return vo;
      }

      @Override
      public boolean create(SysMenuCreateInputVo inputVo) {
	    SysMenu menu = new SysMenu();
	    BeanUtils.copyProperties(inputVo, menu);
	    boolean bl = menuMapper.insert(menu) > 0;
	    this.updateRedis();
	    return bl;
      }

      @Override
      public boolean update(SysMenuUpdateInputVo inputVo) {
	    SysMenu menu = getMenu(inputVo.getId());
	    BeanUtils.copyProperties(inputVo, menu);
	    boolean bl = menuMapper.updateById(menu) > 0;
	    this.updateRedis();
	    return bl;
      }

      @Override
      public boolean delete(String menuId) {
	    List<SysMenu> children = getChildren(menuId);
	    if (children != null && children.size() > 0) {
		  throw new BusinessException(500, "该菜单下还有子级");
	    }
	    boolean bl = menuMapper.deleteById(menuId) > 0;
	    this.updateRedis();
	    return bl;
      }

      @Override
      public List<TreeNode> getTreeSelect() {
	    List<TreeNode> treeNodes = buildTreeNode(getParentMenus());
	    return treeNodes;
      }

      @Override
      public List<SysMenuViewVo> getList() {
	    return buildViewVo(getParentMenus());
      }

      @Override
      public boolean changeStatus(String menuId, Integer status) {
	    return false;
      }

      @Override
      public List<SysMenuPermissionVo> getMenuPermission() {
	    List<SysMenu> parentMenu = this.getParentMenus();
	    List<SysMenuPermissionVo> data =
		    parentMenu.stream()
			    .map(
				    item -> {
					  SysMenuPermissionVo vo = new SysMenuPermissionVo();
					  vo.setId(item.getId());
					  vo.setMenuName(item.getMenuName());
					  List<SysMenuPermissionVo> childrens =
						  getChildrenMenuPermisssion(item.getId());
					  if (childrens != null && childrens.size() > 0) {
						vo.setChildren(childrens);
					  }
					  List<SysMenuPermissionVo> buttons =
						  getMenuButtons(item.getId());
					  if (buttons != null && buttons.size() > 0) {
						vo.setButtons(buttons);
					  }
					  return vo;
				    })
			    .collect(Collectors.toList());
	    return data;
      }

      private List<SysMenuPermissionVo> getChildrenMenuPermisssion(String parentId) {
	    List<SysMenu> menuList = getChildren(parentId);
	    if (menuList != null && menuList.size() > 0) {
		  List<SysMenuPermissionVo> data =
			  menuList.stream()
				  .filter(m -> m.getMenuType().equals(2))
				  .sorted(Comparator.comparing(SysMenu::getSortCode))
				  .map(
					  item -> {
						SysMenuPermissionVo vo = new SysMenuPermissionVo();
						vo.setId(item.getId());
						vo.setMenuName(item.getMenuName());
						List<SysMenuPermissionVo> childrens =
							getChildrenMenuPermisssion(item.getId());
						if (childrens != null && childrens.size() > 0) {
						      vo.setChildren(childrens);
						}
						List<SysMenuPermissionVo> buttons =
							getMenuButtons(item.getId());
						if (buttons != null && buttons.size() > 0) {
						      vo.setButtons(buttons);
						}
						return vo;
					  })
				  .collect(Collectors.toList());
		  return data;
	    }
	    return null;
      }

      private List<SysMenuPermissionVo> getMenuButtons(String parentId) {
	    List<SysMenu> menuList = getChildren(parentId);
	    if (menuList != null && menuList.size() > 0) {
		  List<SysMenuPermissionVo> data =
			  menuList.stream()
				  .filter(m -> m.getMenuType().equals(3))
				  .sorted(Comparator.comparing(SysMenu::getSortCode))
				  .map(
					  item -> {
						SysMenuPermissionVo vo = new SysMenuPermissionVo();
						vo.setId(item.getId());
						vo.setMenuName(item.getMenuName());
						List<SysMenuPermissionVo> childrens =
							getChildrenMenuPermisssion(item.getId());
						vo.setChildren(childrens);
						vo.setButtons(null);
						return vo;
					  })
				  .collect(Collectors.toList());
		  return data;
	    }
	    return null;
      }

      private List<SysMenuViewVo> buildViewVo(List<SysMenu> list) {
	    List<SysMenuViewVo> nodes = new ArrayList<>();
	    if (list != null && list.size() > 0) {
		  list.forEach(
			  dept -> {
				SysMenuViewVo vo = new SysMenuViewVo();
				BeanUtils.copyProperties(dept, vo);
				List<SysMenuViewVo> vos = getChilderenVo(dept.getId());
				vo.setChildren(vos);
				nodes.add(vo);
			  });
	    }
	    return nodes;
      }

      private List<SysMenuViewVo> getChilderenVo(String parentId) {
	    List<SysMenu> list = getChildren(parentId);
	    return buildViewVo(list);
      }

      private List<TreeNode> buildTreeNode(List<SysMenu> list) {
	    List<TreeNode> treeNodes = new ArrayList<>();
	    if (list != null && list.size() > 0) {
		  list.forEach(
			  dept -> {
				TreeNode node = new TreeNode();
				node.setData(dept);
				node.setKey(dept.getId());
				node.setTitle(dept.getMenuName());
				node.setValue(dept.getId());
				List<TreeNode> children = getChildrenNode(dept.getId());
				node.setLeaf(true);
				if (children != null && children.size() > 0) {
				      node.setLeaf(false);
				      node.setChildren(children);
				}
				treeNodes.add(node);
			  });
	    }
	    return treeNodes;
      }

      private List<TreeNode> getChildrenNode(String parentId) {
	    List<SysMenu> list = getChildren(parentId);
	    return buildTreeNode(list);
      }

      private List<SysMenu> getParentMenus() {
	    List<SysMenu> parentMenus =
		    this.getMenuList().stream()
			    .filter(
				    x ->
					    x.getParentId() == null
						    || x.getParentId().equals("0")
						    || "".equals(x.getParentId()))
			    .sorted(Comparator.comparing(SysMenu::getSortCode))
			    .collect(Collectors.toList());
	    return parentMenus;
      }

      private SysMenu getMenu(String menuId) {
	    return menuMapper.selectById(menuId);
      }

      private List<SysMenu> getChildren(String menuId) {
	    List<SysMenu> list =
		    this.getMenuList().stream()
			    .filter(
				    x ->
					    x.getParentId() != null
						    && x.getParentId().toString().equals(menuId))
			    .sorted(Comparator.comparing(SysMenu::getSortCode))
			    .collect(Collectors.toList());
	    return list;
      }
}
